/**
 * 获取文件元素树接口测试用例
 *
 * Created by yangyunze on 2021/01/04.
 */
const chai = require('chai');
const should = chai.should(); // eslint-disable-line no-unused-vars
chai.use(require('chai-http'));

const common = require('./../../common');
const Administrator = require('./../../../models/administrator');
const uri = require('./../uri');
const benchmark = require('./../../../benchmark/analyse-files/cpp');

const fileElements = require('./../../../../phoenix/models/file-elements');

module.exports = describe('/GET file-elements/:id/tree.json', function () {
  const administrator = new Administrator();
  let projectVersion = {};
  let elementsResult;
  let otherElementId;
  const newUserIds = [];
  function url(elementId) {
    return `/file-elements/${elementId}/tree.json`;
  }

  before(function (done) {
    administrator.login()
      .then(() => administrator.createRandomTester())
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject('c++');
      })
      .then((project) => project.createRandomVersion('c++'))
      .then((res) => {
        projectVersion = res;
        done();
      })
      .catch(done);
  });
  after(function (done) {
    administrator.removeUsers(newUserIds)
      .then(() => {
        done();
      })
      .catch(done);
  });

  common.should.be.user(uri, url, 'get');
  common.should.be.tester(uri, url, 'get');

  // 正常请求
  it('it should GET elements tree', function (done) {
    projectVersion.getAllFunctions(benchmark)
      .then((elements) => {
        elementsResult = elements;
        return Promise.all(
          elements.map(
            (element) => new Promise((resolve) => {
              if (!benchmark.result.normal[element.functionName]) {
                resolve();
                return;
              }
              if (!otherElementId) {
                otherElementId = element.functionId;
              }
              const { accessToken } = projectVersion.project.creator.token;
              chai.request(uri)
                .get(url(element.functionId))
                .set('Authorization', `Bearer ${accessToken}`)
                .end((err, res) => {
                  res.should.have.status(200);
                  common.should.be.elementsTree(res.body);
                  common.should.be.equal.tree(
                    res.body.tree,
                    benchmark.result.normal[element.functionName].tree
                  );
                  resolve();
                });
            })
          )
        );
      })
      .then(() => {
        done();
      })
      .catch(done);
  });

  // test kinds parameter
  const kindsGroup = [
    [fileElements.elementKind.class],
    [fileElements.elementKind.class, fileElements.elementKind.function],
  ];
  kindsGroup.forEach((kinds) => {
    it(`it should get elements tree with kinds ${kinds.join(',')}`, function (done) {
      Promise.all(
        elementsResult.map(
          (element) => new Promise((resolve) => {
            const resultKey = `${element.functionName}_${kinds.join('_')}`;
            if (!benchmark.result.kinds[resultKey]) {
              resolve();
              return;
            }
            const { accessToken } = projectVersion.project.creator.token;
            chai.request(uri)
              .get(url(element.functionId))
              .set('Authorization', `Bearer ${accessToken}`)
              .query({ kinds })
              .end((err, res) => {
                res.should.have.status(200);
                common.should.be.elementsTree(res.body);
                common.should.be.equal.tree(
                  res.body.tree,
                  benchmark.result.kinds[resultKey].tree
                );
                resolve();
              });
          })
        )
      )
        .then(() => {
          done();
        })
        .catch(done);
    });
  });

  // test depth parameter
  const depth = 1;
  it(`it should get elements tree with depth ${depth}`, function (done) {
    Promise.all(
      elementsResult.map(
        (element) => new Promise((resolve) => {
          const resultKey = `${element.functionName}_${depth}`;
          if (!benchmark.result.depth[resultKey]) {
            resolve();
            return;
          }
          const { accessToken } = projectVersion.project.creator.token;
          chai.request(uri)
            .get(url(element.functionId))
            .set('Authorization', `Bearer ${accessToken}`)
            .query({ depth })
            .end((err, res) => {
              res.should.have.status(200);
              common.should.be.elementsTree(res.body);
              common.should.be.equal.tree(
                res.body.tree,
                benchmark.result.depth[resultKey].tree
              );
              resolve();
            });
        })
      )
    )
      .then(() => {
        done();
      })
      .catch(done);
  });

  // 不可获取不存在的元素的树
  it('it should fail to get elements tree when the element not exists', function (done) {
    chai.request(uri)
      .get(url('000000000000000000000000'))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .end((err, res) => {
        res.should.have.status(404);
        common.should.be.errorMessage(res.body);
        done();
      });
  });

  // 不可获取他人项目元素的树
  it('it should fail to get elements tree when the project is not yours', function (done) {
    let newUser;
    administrator.createRandomTester()
      .then((newTester) => {
        newUserIds.push(newTester.userId);
        newUser = newTester;
        return newTester.getToken();
      })
      .then(() => {
        chai.request(uri)
          .get(url(otherElementId))
          .set('Authorization', `Bearer ${newUser.token.accessToken}`)
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });
});
